/**
 * @brief MCU 定时器 驱动
 * @author 张勇 41204@qq.com
 * @date 2022-04
 */

#pragma once

#include <stm32f4xx_ll_gpio.h>
#include <stm32f4xx_ll_tim.h>
#include "mcu.h"
#include "_mcu_gpio.h"
#include "share/unios.h"

#ifdef __cplusplus
extern "C" {
#endif

/// @brief Timer Update 中断处理函数 类型
typedef void (*mcu_timer_update_handler_t)(mcu_timer_t *dev);
/// @brief Timer (捕获)输入/(比较)输出 通道的 Update 中断处理函数 类型
typedef void (*mcu_timer_ch_update_handler_t)(mcu_timer_ch_t *ch);

/// @brief Timer 接口数据结构
typedef struct _mcu_timer {
    TIM_TypeDef *timx;      ///< TIMx
    /// Timer 主工作频率(Hz)（计数时钟频率）
    uint32_t freq_main;
    /// Timer 调制信号频率(Hz)（决定了重装载计数值），不能大于 freq_main
    uint32_t freq_mod;
    /// update 周期(us): 计算多长时间会 update 一次
    unios_us_t update_period_us;
    /// update 中断处理函数
    mcu_timer_update_handler_t update_handler;
    /// 所有的子通道指针    
    mcu_timer_ch_t *chs[4];
} mcu_timer_t;
    
/// @brief Timer (捕获)输入/(比较)输出 通道 数据结构
typedef struct _mcu_timer_ch {
    mcu_timer_t *parent;    ///< 所属的 Timer
    uint32_t chidx;         ///< 通道编号(1~4)
    uint32_t active_level;  ///< 有效电平

    /// 配置 Timer 通道 GPIO 引脚功能复用关系 的函数指针
    mcu_gpio_mux_func_init_t chpin_mux_init;
    /// Timer (捕获)输入/(比较)输出 通道的 Update 中断处理函数
    mcu_timer_ch_update_handler_t update_handler;
    
    /// 信号占空比（单位: 0.01%）
    uint32_t duty;
    /// 信号持续时间(us): duration_us >0 时持续 duration_us 后自动停止; =0 时不自动停止，需要调用 mcu_timer_ch_oc_stop() 停止
    unios_us_t duration_us;
    /// 正在播放的音符音乐
    const Note *notes;
    /// 音符音乐播放速度（单位: 1%）
    const uint32_t note_speed;
} mcu_timer_ch_t;

/// @brief 用于定义 Timer 引脚复用关系配置函数的宏
#define _TIMER_FPIN_MUX(TIMx, FPIN, PIN, AF) \
    static inline mcu_gpio_num_t TIMx##_##FPIN##_USE_##PIN() { return mcu_gpio_pinmux_config(MCU_GPIO_NUM_##PIN, LL_GPIO_AF_##AF) ? MCU_GPIO_NUM_MAX : MCU_GPIO_NUM_##PIN; }

/// @brief 定义各个 Timer 引脚复用关系配置函数
_TIMER_FPIN_MUX(TIM1 , BKIN, PA6 , 1);
_TIMER_FPIN_MUX(TIM1 , CH1N, PA7 , 1);
_TIMER_FPIN_MUX(TIM1 , CH1 , PA8 , 1);
_TIMER_FPIN_MUX(TIM1 , CH2 , PA9 , 1);
_TIMER_FPIN_MUX(TIM1 , CH3 , PA10, 1);
_TIMER_FPIN_MUX(TIM1 , CH4 , PA11, 1);
_TIMER_FPIN_MUX(TIM1 , ETR , PA12, 1);
_TIMER_FPIN_MUX(TIM1 , CH2N, PB0 , 1);
_TIMER_FPIN_MUX(TIM1 , CH3N, PB1 , 1);
_TIMER_FPIN_MUX(TIM1 , BKIN, PB12, 1);
_TIMER_FPIN_MUX(TIM1 , CH1N, PB13, 1);
_TIMER_FPIN_MUX(TIM1 , CH2N, PB14, 1);
_TIMER_FPIN_MUX(TIM1 , CH3N, PB15, 1);
_TIMER_FPIN_MUX(TIM1 , ETR , PE7 , 1);
_TIMER_FPIN_MUX(TIM1 , CH1N, PE8 , 1);
_TIMER_FPIN_MUX(TIM1 , CH1 , PE9 , 1);
_TIMER_FPIN_MUX(TIM1 , CH2N, PE10, 1);
_TIMER_FPIN_MUX(TIM1 , CH2 , PE11, 1);
_TIMER_FPIN_MUX(TIM1 , CH3N, PE12, 1);
_TIMER_FPIN_MUX(TIM1 , CH3 , PE13, 1);
_TIMER_FPIN_MUX(TIM1 , CH4 , PE14, 1);
_TIMER_FPIN_MUX(TIM1 , BKIN, PE15, 1);

_TIMER_FPIN_MUX(TIM2 , ETR , PA0 , 1);
_TIMER_FPIN_MUX(TIM2 , CH1 , PA0 , 1);
_TIMER_FPIN_MUX(TIM2 , CH2 , PA1 , 1);
_TIMER_FPIN_MUX(TIM2 , CH3 , PA2 , 1);
_TIMER_FPIN_MUX(TIM2 , CH4 , PA3 , 1);
_TIMER_FPIN_MUX(TIM2 , ETR , PA5 , 1);
_TIMER_FPIN_MUX(TIM2 , CH1 , PA5 , 1);
_TIMER_FPIN_MUX(TIM2 , ETR , PA15, 1);
_TIMER_FPIN_MUX(TIM2 , CH1 , PA15, 1);
_TIMER_FPIN_MUX(TIM2 , CH2 , PB3 , 1);
_TIMER_FPIN_MUX(TIM2 , CH3 , PB10, 1);
_TIMER_FPIN_MUX(TIM2 , CH4 , PB11, 1);

_TIMER_FPIN_MUX(TIM3 , CH1 , PA6 , 2);
_TIMER_FPIN_MUX(TIM3 , CH2 , PA7 , 2);
_TIMER_FPIN_MUX(TIM3 , CH3 , PB0 , 2);
_TIMER_FPIN_MUX(TIM3 , CH4 , PB1 , 2);
_TIMER_FPIN_MUX(TIM3 , CH1 , PB4 , 2);
_TIMER_FPIN_MUX(TIM3 , CH2 , PB5 , 2);
_TIMER_FPIN_MUX(TIM3 , CH1 , PC6 , 2);
_TIMER_FPIN_MUX(TIM3 , CH2 , PC7 , 2);
_TIMER_FPIN_MUX(TIM3 , CH3 , PC8 , 2);
_TIMER_FPIN_MUX(TIM3 , CH4 , PC9 , 2);
_TIMER_FPIN_MUX(TIM3 , ETR , PD2 , 2);

_TIMER_FPIN_MUX(TIM4 , CH1 , PB6 , 2);
_TIMER_FPIN_MUX(TIM4 , CH2 , PB7 , 2);
_TIMER_FPIN_MUX(TIM4 , CH3 , PB8 , 2);
_TIMER_FPIN_MUX(TIM4 , CH4 , PB9 , 2);
_TIMER_FPIN_MUX(TIM4 , CH1 , PD12, 2);
_TIMER_FPIN_MUX(TIM4 , CH2 , PD13, 2);
_TIMER_FPIN_MUX(TIM4 , CH3 , PD14, 2);
_TIMER_FPIN_MUX(TIM4 , CH4 , PD15, 2);
_TIMER_FPIN_MUX(TIM4 , ETR , PE0 , 2);

_TIMER_FPIN_MUX(TIM5 , CH1 , PA0 , 2);
_TIMER_FPIN_MUX(TIM5 , CH2 , PA1 , 2);
_TIMER_FPIN_MUX(TIM5 , CH3 , PA2 , 2);
_TIMER_FPIN_MUX(TIM5 , CH4 , PA3 , 2);
_TIMER_FPIN_MUX(TIM5 , CH1 , PH10, 2);
_TIMER_FPIN_MUX(TIM5 , CH2 , PH11, 2);
_TIMER_FPIN_MUX(TIM5 , CH3 , PH12, 2);
_TIMER_FPIN_MUX(TIM5 , CH4 , PI0 , 2);

/// @brief 获取 Timer 的 CK_INT 时钟频率
uint32_t mcu_timer_get_ck_int(mcu_timer_t *dev);
/// @brief 获取 Timer 的 update 中断号
uint32_t mcu_timer_get_update_irqn(mcu_timer_t *dev);

/// @brief Timer 初始化
/// @param dev Timer 设备指针
/// @param clksrc Timer 时钟来源
/// @param clksrc_opt (可选) Timer 时钟来源的可选参数，具体类型根据 clksrc 来确定
/// @param freq_main Timer 主工作频率(Hz)（计数时钟频率）
/// @param freq_mod  Timer 调制信号频率(Hz)（决定了重装载计数值），不能大于 freq_main
/// @return 标准错误码
std_err_t mcu_timer_init(mcu_timer_t *dev, mcu_timer_clksrc_t clksrc, void *clksrc_opt, uint32_t freq_main, uint32_t freq_mod);
/// @brief Timer 设置调制频率(Hz)
std_err_t mcu_timer_set_freq_mod(mcu_timer_t *dev, uint32_t freq_mod);
/// @brief Timer 获取当前调制频率(Hz)
static inline uint32_t mcu_timer_get_freq_mod(mcu_timer_t *dev) { return dev->freq_mod; }
/// @brief Timer 启动计时
std_err_t mcu_timer_start(mcu_timer_t *dev);
/// @brief Timer 停止计时
std_err_t mcu_timer_stop(mcu_timer_t *dev);

/// @brief Timer 的 update 中断处理函数 stub
void mcu_timer_update_isr_stub(mcu_timer_t *dev);
/// @brief 设置 Timer 的 update 中断处理函数
static inline void mcu_timer_setup_update_handler(mcu_timer_t *dev, mcu_timer_update_handler_t handler) { dev->update_handler = handler; }
/// @brief 启用 Timer 更新中断
std_err_t mcu_timer_enable_update_irq(mcu_timer_t *dev);
/// @brief 禁用 Timer 更新中断
std_err_t mcu_timer_disable_update_irq(mcu_timer_t *dev);

/// @brief 初始化 Timer (捕获)输入/(比较)输出 通道 使用的 GPIO 引脚
std_err_t mcu_timer_ch_init(mcu_timer_ch_t *ch);
/// @brief 设置 Timer (捕获)输入/(比较)输出 通道的 update 中断处理函数
static inline void mcu_timer_ch_setup_update_handler(mcu_timer_ch_t *ch, mcu_timer_ch_update_handler_t handler) { ch->update_handler = handler; }

/// @brief 设置 Timer (比较)输出 通道的 调制占空比
/// @param duty 调制占空比（单位: 0.01%）
std_err_t mcu_timer_ch_oc_set_duty(mcu_timer_ch_t *ch, uint32_t duty);
/// @brief 获取 Timer (比较)输出 通道的 调制占空比
/// @return 调制占空比（单位: 0.01%）
static inline uint32_t mcu_timer_ch_oc_get_duty(mcu_timer_ch_t *ch) { return ch ? ch->duty : 0; }
/// @brief Timer (比较)输出 通道启动
/// @param duration_us >0 时持续 duration_us 后自动停止; =0 时不自动停止，需要调用 mcu_timer_ch_oc_stop() 停止
std_err_t mcu_timer_ch_oc_start(mcu_timer_ch_t *ch, unios_us_t duration_us);
/// @brief Timer (比较)输出 通道停止
std_err_t mcu_timer_ch_oc_stop(mcu_timer_ch_t *ch);
/// @brief Timer (比较)输出 通道播放音符音乐
/// @param notes 音符音乐(最后一个音符为无效时表示结束)
/// @param speed 播放速度（单位: 1%）
std_err_t mcu_timer_ch_oc_play_notes(mcu_timer_ch_t *ch, const Note *notes, uint32_t speed);

/// @brief 定义命名的 Timer
#define TIMER_DEFINE(NAME, TIMx) \
    static mcu_timer_t _##NAME = { .timx = TIMx, .update_handler = NULL, .chs = {NULL, NULL, NULL, NULL} }; \
    mcu_timer_t *NAME = &_##NAME; \
    _RAMCODE_ void TIMx##_update_isr() { mcu_timer_update_isr_stub(NAME); } \
    std_err_t NAME##_Init(mcu_timer_clksrc_t clksrc, void *clksrc_opt, uint32_t freq_main, uint32_t freq_mod) { return mcu_timer_init(NAME, clksrc, clksrc_opt, freq_main, freq_mod); } \
    std_err_t NAME##_EnableUpdateIrq() { return mcu_timer_enable_update_irq(NAME); } \
    std_err_t NAME##_DisableUpdateIrq() { return mcu_timer_disable_update_irq(NAME); } \
    std_err_t NAME##_SetFreqMod(uint32_t freq_mod) { return mcu_timer_set_freq_mod(NAME, freq_mod); } \
    std_err_t NAME##_Start() { return mcu_timer_start(NAME); } \
    std_err_t NAME##_Stop()  { return mcu_timer_stop(NAME); }

/// @brief 定义命名的 Timer 通道
#define TIMERCH_DEFINE(CHNAME, TMNAME, TIMx, CHIDX, PIN, ACTIVE_LEVEL) \
    static mcu_timer_ch_t _##CHNAME = { .parent = &_##TMNAME, .chidx = CHIDX, .active_level = ACTIVE_LEVEL, .duty = 5000, .notes = NULL, .note_speed = 100, .chpin_mux_init = TIMx##_CH##CHIDX##_USE_##PIN, .update_handler = NULL }; \
    mcu_timer_ch_t *CHNAME = &_##CHNAME; \
    std_err_t CHNAME##_Init()                   { return mcu_timer_ch_init(CHNAME); } \
	std_err_t CHNAME##_OcSetDuty(uint32_t duty) { return mcu_timer_ch_oc_set_duty(CHNAME, duty); } \
	uint32_t  CHNAME##_OcGetDuty(void)          { return mcu_timer_ch_oc_get_duty(CHNAME); } \
	std_err_t CHNAME##_OcStart(unios_us_t us)   { return mcu_timer_ch_oc_start(CHNAME, us); } \
	std_err_t CHNAME##_OcStop(void)             { return mcu_timer_ch_oc_stop(CHNAME); } \
	std_err_t CHNAME##_OcPlayNotes(const Note *notes, uint32_t speed) { return mcu_timer_ch_oc_play_notes(CHNAME, notes, speed); }


#ifdef __cplusplus
} //extern "C"
#endif
